/**
 * Copyright (c) 2024-2025 National Fundamental Software of China Co., Ltd.
 *
 * You should have find a copy of NFSChina License. If not, please contact us
 * by email <os_support@nfschina>
 *
**/

/*
    SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

import QtQuick 2.15
import QtGraphicalEffects 1.15
// Deliberately imported after QtQuick to avoid missing restoreMode property in Binding. Fix in Qt 6.
import QtQml 2.15
import QtQuick.Controls 2.5

import org.kde.kquickcontrolsaddons 2.0
import org.kde.kwindowsystem 1.0
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.1 as PlasmaCore

import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.kirigami 2.12 as Kirigami

import org.kde.plasma.private.shell 2.0

import org.kde.plasma.private.kicker 0.1 as Kicker

import "code/tools.js" as Tools

/* TODO
 * Reverse middleRow layout + keyboard nav + filter list text alignment in rtl locales.
 * Keep cursor column when arrow'ing down past non-full trailing rows into a lower grid.
 * Make DND transitions cleaner by performing an item swap instead of index reinsertion.
*/

Kicker.DashboardWindow {
    id: root
    property bool smallScreen: ((Math.floor(width / PlasmaCore.Units.iconSizes.huge) <= 22) || (Math.floor(height / PlasmaCore.Units.iconSizes.huge) <= 14))
    property real scaleFactor: PlasmaCore.Units.devicePixelRatio;

    property int iconSize: smallScreen ? PlasmaCore.Units.iconSizes.large : PlasmaCore.Units.iconSizes.huge
    property int cellSize: iconSize + (2 * PlasmaCore.Theme.mSize(PlasmaCore.Theme.defaultFont).height)
        + (2 * PlasmaCore.Units.smallSpacing)
        + (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom,
                        highlightItemSvg.margins.left + highlightItemSvg.margins.right))
    property int columns: Math.floor(((smallScreen ? 85 : 80)/100) * Math.ceil(width / cellSize))
    property bool searching: searchHeading.searchText !== ""
    property var widgetExplorer: null
    property string currentTitle: ""
    keyEventProxy: searchHeading.searchField
    backgroundColor: blurEffectValid ? "#60303030" : "#f4f4f4"

    property bool blurEffectValid: false

    onKeyEscapePressed: {
        if (searching) {
            searchHeading.clear()
        } else {
            root.toggle();
        }
    }

    onWheelWindowChange: (down) => {
        if (allAppsGridView.visible) {
            allAppsGridView.turningPage(down);
        } else if (runnerGrid.visible) {
            runnerGrid.turningPage(down);
        }
    }

    onVisibleChanged: {
        reset();

        if (visible) {
            preloadAllAppsTimer.restart();
        }
    }

    onSearchingChanged: {
        if (!searching) {
            reset();
        } else {
            filterList.currentIndex = -1;
        }
    }

    function reset() {
        searchHeading.clear()
        // globalFavoritesGrid.currentIndex = -1;
        // systemFavoritesGrid.currentIndex = -1;
        filterList.currentIndex = 0;
        funnelModel.sourceModel = rootModel.modelForRow(filterList.currentIndex);
        mainGrid.model = funnelModel
        mainGrid.currentIndex = -1;
        filterListScrollArea.focus = true;
        filterList.model = rootModel
    }

    function updateWidgetExplorer() {
       if (root.widgetExplorer) {
            root.widgetExplorer.destroy();
            root.widgetExplorer = null;
        }
    }

    mainItem: MouseArea {
        id: rootItem

        anchors.fill: parent
        
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
        LayoutMirroring.childrenInherit: true

        PlasmaCore.DataSource {
        id: executable
            engine: "executable"
            connectedSources: []
            onNewData: {
                blurEffectValid = data["stdout"].toString().includes("true");
                executable.disconnectSource(sourceName)
            }

            function exec(cmd) {
                executable.connectSource(cmd)
            }
        }

        Component.onCompleted: {
            if (plasmoid.showLauncher) {
                root.show()
            }
            executable.exec('dbus-send --print-reply --dest=org.kde.KWin /Effects org.kde.kwin.Effects.areEffectsSupported array:string:"blur"')
            PlasmaCore.Theme.themeChanged.connect(updateBgEffect);
            if (plasmoid.hasOwnProperty("activationTogglesExpanded")) {
                plasmoid.activationTogglesExpanded = true
            }
        }
        Connections {
            target: kicker

            function onReset() {
                if (!root.searching) {
                    filterList.applyFilter();
                    funnelModel.reset();
                }
            }

            function onDragSourceChanged() {
                if (!kicker.dragSource) {
                    // FIXME TODO HACK: Reset all views post-DND to work around
                    // mouse grab bug despite QQuickWindow::mouseGrabberItem==0x0.
                    // Needs a more involved hunt through Qt Quick sources later since
                    // it's not happening with near-identical code in the menu repr.
                    rootModel.refresh();
                }
            }
        }

        KWindowSystem {
            id: kwindowsystem
        }

        Component {
            id: widgetExplorerComponent

            WidgetExplorer { showSpecialFilters: false }
        }

        Connections {
            target: plasmoid
            function onUserConfiguringChanged() {
                if (plasmoid.userConfiguring) {
                    root.hide()
                }
            }
            // function onShowLauncherChanged() {
            //     if (plasmoid.showLauncher) {
            //         root.show()
            //     }
            // }
        }

        PlasmaComponents.Menu {
            id: contextMenu

            PlasmaComponents.MenuItem {
                action: plasmoid.action("configure")
            }
        }

        PlasmaExtras.Heading {
            id: dummyHeading

            visible: false

            width: 0

            level: 1
        }

        TextMetrics {
            id: headingMetrics

            font: dummyHeading.font
        }

        Kicker.FunnelModel {
            id: funnelModel

            onSourceModelChanged: {
                if (mainColumn.visible) {
                    mainGrid.currentIndex = -1;
                    mainGrid.forceLayout();
                }
            }
        }

        Timer {
            id: preloadAllAppsTimer

            property bool done: false

            interval: 1000
            repeat: false

            onTriggered: {
                if (done || root.searching) {
                    return;
                }

                for (var i = 0; i < rootModel.count; ++i) {
                    var model = rootModel.modelForRow(i);

                    if (model.description === "KICKER_ALL_MODEL") {
                        // allAppsGrid.model = model;
                        done = true;
                        break;
                    }
                }
            }

            function defer() {
                if (running && !done) {
                    restart();
                }
            }
        }

        Kicker.ContainmentInterface {
            id: containmentInterface
        }

        /** 搜索框**/
        Search {
            id: searchHeading
            anchors {
                top: parent.top
                topMargin: PlasmaCore.Units.gridUnit * 1.5
                horizontalCenter: parent.horizontalCenter
            }
           
            onSearchTextChanged: {
                runnerModel.query = searchHeading.searchText;
            }

        }
        /** 搜索框 End**/

        Rectangle {
            id: switch_normal
            width: 35 * scaleFactor
            height: width
            radius: 8
            anchors {
                right: parent.right
                rightMargin: 29 * scaleFactor
                top: parent.top
                topMargin: PlasmaCore.Units.gridUnit * 1.5
            }
            color:"transparent"
            Kirigami.Icon {
                id : watermarkIcon
                anchors {
                    verticalCenter: parent.verticalCenter
                    horizontalCenter: parent.horizontalCenter
                }
                width: 16 * scaleFactor
                height: width
                source: "launcher_normal"
            }
            readonly property string tipContent: i18n("default mode")
            ToolTip {
                id: allTip
                delay: Kirigami.Units.toolTipDelay
            }
            MouseArea {
                anchors.fill: parent
                hoverEnabled: true
                onClicked: {
                    containmentInterface.createApplet(plasmoid ,"org.kde.plasma.kickoff")
                }
                onEntered: {
                    switch_normal.color = Qt.rgba(255, 255, 255, 0.5)
                    allTip.show(switch_normal.tipContent, 2000)
                }

                onExited: {
                    switch_normal.color = "transparent"
                    allTip.hide()
                }
            }
        }
        // 全部应用ui
        GridViewStack {
            id: allAppsGridView
            anchors {
                top: searchHeading.top
                topMargin: PlasmaCore.Units.gridUnit * (smallScreen ? 2 : 10)
                bottom: parent.bottom
                horizontalCenter: parent.horizontalCenter
            }
            dataModel: rootModel
            width: Math.max(parent.width *0.6, 650) //parent.width - (438 * 2 * scaleFactor)
            height: parent.height * 0.5//parent.height - 300 * scaleFactor
            margins: 20
            visible: globalFavoritesGrid.currentShowAppsPage === 0 && !root.searching
        }

        GridViewStack {
            id: runnerGrid
            anchors {
                top: searchHeading.top
                topMargin: PlasmaCore.Units.gridUnit * (smallScreen ? 2 : 10)
                bottom: parent.bottom
                horizontalCenter: parent.horizontalCenter
            }
            dataModel: runnerModel
            width: Math.max(parent.width *0.6, 650) //parent.width - (438 * 2 * scaleFactor)
            height: parent.height * 0.5//parent.height - 300 * scaleFactor
            margins: 20
            visible: opacity !== 0.0
            opacity: root.searching ? 1.0 : 0.0
            z: (opacity === 1.0) ? 1 : 0
            onOpacityChanged: {
                if (opacity === 1.0) {
                    mainColumn.visibleGrid = runnerGrid;
                }
            }
        }

        Row {
            id: middleRow
            anchors {
                top: parent.top
                bottom: parent.bottom
                // topMargin: PlasmaCore.Units.gridUnit * (smallScreen ? 8 : 10)
                left: parent.left
            }

            width: (root.columns * root.cellSize) + (scaleFactor * spacing)

            spacing: PlasmaCore.Units.gridUnit * scaleFactor

            Item {
                id: favoritesColumn
                anchors {
                    top: parent.top
                    topMargin: PlasmaCore.Units.gridUnit
                    bottomMargin: PlasmaCore.Units.gridUnit
                    bottom: parent.bottom
                }

                width:  65 * scaleFactor
                property int columns: 3

                SideBar {
                    id: globalFavoritesGrid
                    width: 64 * scaleFactor
                    // height: rightContent.height
                    squareButtonWidth: 36 * scaleFactor
                    anchors {
                        left: parent.left
                        top: parent.top
                        bottom: parent.bottom
                    }
                }
                Rectangle {
                    width: 1
                    color: "#CCCCCC"
                    height: parent.height + PlasmaCore.Units.gridUnit * 2
                    opacity: 0.4
                    anchors {
                        left: globalFavoritesGrid.right
                        top: parent.top
                        topMargin: -PlasmaCore.Units.gridUnit
                    }
                }
            }


            Item {
                id: mainColumn

                anchors {
                    fill: allAppsGridView
                    top: parent.top
                    topMargin: PlasmaCore.Units.gridUnit * (smallScreen ? 6 : 8)// root.height > 1079 ? PlasmaCore.Units.gridUnit * (smallScreen ? 6 : 8) : PlasmaCore.Units.gridUnit * (smallScreen ? 6 : 8)
                }
                width: root.width //(columns * root.cellSize) + PlasmaCore.Units.gridUnit
                height: root.height - PlasmaCore.Units.gridUnit * (smallScreen ? 8 : 10) //Math.floor(parent.height / root.cellSize) * root.cellSize

                property int columns: root.columns - favoritesColumn.columns - filterListColumn.columns
                property Item visibleGrid: mainGrid

                function tryActivate(row, col) {
                    if (visibleGrid) {
                        visibleGrid.tryActivate(row, col);
                    }
                }

                Item {
                    id: filterListColumn
                    anchors {
                        // top: parent.top
                        // topMargin: parent.height / 4
                        // bottom: parent.bottom
                        verticalCenter: parent.verticalCenter

                        right: mainGridContainer.left
                        rightMargin: 10
                    }

                    width: root.cellSize / 2 // columns * root.cellSize
                    height: Math.max(mainGridContainer.height, 600) // columns * root.cellSize
                    property int columns: 8

                    PlasmaExtras.ScrollArea {
                        id: filterListScrollArea

                        x: root.visible ? 0 : PlasmaCore.Units.gridUnit

                        Behavior on x { SmoothedAnimation { duration: PlasmaCore.Units.longDuration; velocity: 0.01 } }
                        height: parent.height    
                        anchors {
                            fill:parent
                        }
                        enabled: !root.searching

                        property alias currentIndex: filterList.currentIndex

                        opacity: root.visible && globalFavoritesGrid.currentShowAppsPage === 1 ? (root.searching ? 0.30 : 1.0) : 0

                        Behavior on opacity { SmoothedAnimation { duration: PlasmaCore.Units.longDuration; velocity: 0.01 } }

                        verticalScrollBarPolicy: (opacity === 1.0) ? Qt.ScrollBarAsNeeded : Qt.ScrollBarAlwaysOff
                        onEnabledChanged: {
                            if (!enabled) {
                                filterList.currentIndex = -1;
                            }
                        }

                        onCurrentIndexChanged: {
                            focus = (currentIndex !== -1);
                        }
                        ListView {
                            id: filterList
                            focus: true
                            property bool allApps: false
                            property int eligibleWidth: width
                            property int hItemMargins: Math.max(highlightItemSvg.margins.left + highlightItemSvg.margins.right,
                                listItemSvg.margins.left + listItemSvg.margins.right)

                            anchors {
                                horizontalCenter:parent.horizontalCenter
                                // verticalCenter: parent.verticalCenter
                                top: parent.top
                                topMargin: Math.max((filterList.height - (parent.width * count +  spacing * (count - 1))) / 2 + spacing / 2, 20)
                            }
                            visible: globalFavoritesGrid.currentShowAppsPage === 1
                            model: rootModel
                            boundsBehavior: Flickable.StopAtBounds
                            snapMode: ListView.SnapToItem
                            spacing: root.height > 1079 ? cellSize / 4 : cellSize / 6
                            keyNavigationWraps: true

                            delegate: MouseArea {
                                id: item
                                signal actionTriggered(string actionId, variant actionArgument)
                                signal aboutToShowActionMenu(variant actionMenu)
                                property var m: model
                                property int mouseCol
                                property bool hasActionList: ((model.favoriteId !== null)
                                    || (("hasActionList" in model) && (model.hasActionList === true)))
                                property Item menu: actionMenu
                                width: parent.width // cellSize / 4
                                height: width

                                Accessible.role: Accessible.MenuItem
                                Accessible.name: model.display
                                Component.onCompleted: {
                                    if (model.index == 0) {
                                        root.currentTitle = model.display;
                                    }
                                }
                                acceptedButtons: Qt.LeftButton | Qt.RightButton

                                hoverEnabled: true

                                onContainsMouseChanged: {
                                    if (!containsMouse) {
                                        updateCurrentItemTimer.stop();
                                    }
                                }

                                onPositionChanged: mouse => { // Lazy menu implementation.
                                    mouseCol = mouse.x;
                                    if (justOpenedTimer.running || ListView.view.currentIndex === 0 || index === ListView.view.currentIndex) {
                                        updateCurrentItem();
                                    } else if ((index === ListView.view.currentIndex - 1) && mouse.y < (height - 6)
                                        || (index === ListView.view.currentIndex + 1) && mouse.y > 5) {

                                        if (mouse.x > ListView.view.eligibleWidth - 5) {
                                            updateCurrentItem();
                                        }
                                    } else if (mouse.x > ListView.view.eligibleWidth) {
                                        updateCurrentItem();
                                    }

                                    updateCurrentItemTimer.restart();
                                }

                                onPressed: mouse => {
                                    if (mouse.buttons & Qt.RightButton) {
                                        if (hasActionList) {
                                            openActionMenu(item, mouse.x, mouse.y);
                                        }
                                    }
                                }

                                onClicked: mouse => {
                                    if (mouse.button === Qt.LeftButton) {
                                        updateCurrentItem();
                                    }
                                }

                                onAboutToShowActionMenu: {
                                    var actionList = hasActionList ? model.actionList : [];
                                    Tools.fillActionMenu(i18n, actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId);
                                }

                                onActionTriggered: {
                                    if (Tools.triggerAction(ListView.view.model, model.index, actionId, actionArgument) === true) {
                                        plasmoid.expanded = false;
                                    }
                                }

                                function openActionMenu(visualParent, x, y) {
                                    root.isHoldDisplay = true;
                                    aboutToShowActionMenu(actionMenu);
                                    actionMenu.visualParent = visualParent;
                                    actionMenu.open(x, y);
                                }

                                function updateCurrentItem() {
                                    ListView.view.currentIndex = index;
                                    root.currentTitle = model.display;
                                    ListView.view.eligibleWidth = Math.min(width, mouseCol);
                                }

                                ActionMenu {
                                    id: actionMenu
                                    onActionClicked: {
                                        actionTriggered(actionId, actionArgument);
                                    }
                                }

                                Timer {
                                    id: updateCurrentItemTimer

                                    interval: 50
                                    repeat: false

                                    onTriggered: parent.updateCurrentItem()
                                }
                                PlasmaCore.IconItem {
                                    id: label
                                    anchors.centerIn: parent
                                    source: model.decoration
                                    width: cellSize / 4
                                    usesPlasmaTheme: false
                                    height: width
                                }
                            }

                            highlight: Rectangle {
                                visible: filterList.currentItem
                                width: parent.width
                                height:width
                                color: "#00000000"
                                x: filterList.currentItem.x
                                y: filterList.currentItem.y
                                Rectangle {
                                    anchors {
                                        horizontalCenter:parent.horizontalCenter

                                        verticalCenter: parent.verticalCenter
                                    }
                                    width: cellSize / 4 + 8
                                    height: width
                                    radius: width / 2
                                    color: "#ffffff"
                                    opacity: 0.5
                                }

                            }

                            highlightFollowsCurrentItem: false
                            highlightMoveDuration: 0
                            highlightResizeDuration: 0

                            onCurrentIndexChanged: applyFilter()

                            onCountChanged: {
                                var width = 0;

                                for (var i = 0; i < rootModel.count; ++i) {
                                    headingMetrics.text = rootModel.labelForRow(i);

                                    if (headingMetrics.width > width) {
                                        width = headingMetrics.width;
                                    }
                                }

                                filterListColumn.columns = Math.ceil(width / root.cellSize);
                                filterListScrollArea.width = width + hItemMargins + (PlasmaCore.Units.gridUnit * 2);
                            }

                            function applyFilter() {
                                if (!root.searching && currentIndex >= 0) {

                                    if (preloadAllAppsTimer.running) {
                                        preloadAllAppsTimer.stop();
                                    }
                                    
                                    var model = rootModel.modelForRow(currentIndex);
                                    if (model.description === "KICKER_ALL_MODEL") {
                                        // allAppsGrid.model = model;
                                        allApps = true;
                                        funnelModel.sourceModel = null;
                                        preloadAllAppsTimer.done = true;
                                    } else {
                                        funnelModel.sourceModel = model;
                                        allApps = false;
                                    }
                                } else {
                                    funnelModel.sourceModel = null;
                                    allApps = false;
                                }
                            }

                            Keys.onPressed: event => {
                                if (event.key === Qt.Key_Left) {
                                    event.accepted = true;

                                    const currentRow = Math.max(0, Math.ceil(currentItem.y / mainGrid.cellHeight) - 1);
                                    mainColumn.tryActivate(currentRow, mainColumn.columns - 1);
                                } else if (event.key === Qt.Key_Tab) {
                                    event.accepted = true;
                                    // systemFavoritesGrid.tryActivate(0, 0);
                                } else if (event.key === Qt.Key_Backtab) {
                                    event.accepted = true;
                                    mainColumn.tryActivate(0, 0);
                                }
                            }
                        }
                    }
                }

                Rectangle {
                    id: mainGridContainer

                    anchors {
                        // top: parent.top
                        horizontalCenter:parent.horizontalCenter

                        verticalCenter: parent.verticalCenter
                    }
                    width: root.width > 1919 ? 860 * scaleFactor : parent.width / 2
                    height: root.height > 1079 ?  720 * scaleFactor : root.height  / 5 * 4
                    z: (opacity === 1.0) ? 1 : 0
                    color: "#180E0F0F"
                    radius: 24
                    clip: true
                    visible: opacity !== 0.0

                    opacity: {
                        if (root.searching) {
                            return 0.0;
                        }

                        if (globalFavoritesGrid.currentShowAppsPage === 0) {
                            return 0.0;
                        }

                        return 1.0;
                    }

                    onOpacityChanged: {
                        if (opacity === 1.0) {
                            mainColumn.visibleGrid = mainGrid;
                        }
                    }

                    PlasmaComponents3.Label {
                        id: mainColumnLabelUnderline
                        visible: mainGrid.count
                        anchors {
                            top: parent.top
                            topMargin: 24 * scaleFactor
                            horizontalCenter: parent.horizontalCenter
                        }
                        height: 45 * scaleFactor
                        text: root.currentTitle
                        font.pointSize: root.height > 1079 ? 32 : 20
                    }


                    ItemGridView {
                        id: mainGrid

                        anchors {
                            top: mainColumnLabelUnderline.bottom
                            topMargin: 63
                            horizontalCenter: parent.horizontalCenter
                        }
                        width: parent.width - 50 * 2
                        height: parent.height - 63 * 2 - 90
                        cellWidth: width / 4 // root.cellSize + 60 * scaleFactor
                        cellHeight: height / 3
                        iconSize: root.iconSize

                        model: funnelModel

                        onCurrentIndexChanged: {
                            preloadAllAppsTimer.defer();
                        }

                        onKeyNavLeft: {
                            var row = currentRow();
                        }

                        onKeyNavRight: {
                            filterListScrollArea.focus = true;
                        }
                    }
                }


                Keys.onPressed: event => {
                    if (event.key === Qt.Key_Tab) {
                        event.accepted = true;

                        if (filterList.enabled) {
                            filterList.forceActiveFocus();
                        }
                    } else if (event.key === Qt.Key_Backtab) {
                        event.accepted = true;
                         if (globalFavoritesGrid.enabled) {
                            globalFavoritesGrid.tryActivate(0, 0);
                        }
                    }
                }
            }
        }

        onPressed: mouse => {
            if (mouse.button === Qt.RightButton) {
                contextMenu.open(mouse.x, mouse.y);
            }
        }

        onClicked: mouse => {
            if (mouse.button === Qt.LeftButton) {
                root.toggle();
            }
        }
    }

    Component.onCompleted: {
        rootModel.refresh();
    }
}
